package fr.ants.model;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import fr.ants.model.ai.pathfinding.AStarData;

/** 
 * <p>Node on the map.</>
 * <p>It can contain:</p>
 * <ul><li>an Ant</§li>
 * <li>a Nest</li>
 * <li>a Resource</li></ul>
 *
 * @author Vianney DUPOY DE GUITARD
 */
public class Node {

	/** Maximum difficulty of a node. */
	public static final int MAX_DIFFICULTY = 100;

	/** Maximum quantity of pheromones possible. */
	public static final int MAX_PHEROMONES = 500;

	/** Difficulty of the node (the harder it is, the harder ants will be slow on it), from 0 to 100. */
	private int difficulty = 0;

	/** Amount of pheromones on this node. */
	private float pheromoneLevel;

	/** X Position of the node. */
	private final int xPos;

	/** Y Position of the node. */
	private final int yPos;

	/** Ants on this node, if any. */
	private BlockingQueue<Ant> ants = new LinkedBlockingQueue<Ant>();

	/** Resource on this node, if any. */
	private Resource resource;

	/** Nest on this node, if any. */
	private Nest nest;

	/** Data used for A* algorithm. */
	private AStarData aStarData = new AStarData();

	/**
	 * Creates a new node, with its position.
	 * @param x : x position on the grid.
	 * @param y : y position on the grid.
	 */
	public Node(int x, int y) {
		xPos = x;
		yPos = y;
	}

	/**
	 * Creates a new node, with its position.
	 * @param x : x position on the grid.
	 * @param y : y position on the grid.
	 * @param d : difficulty of the node.
	 */
	public Node(int x, int y, int d) {
		xPos = x;
		yPos = y;
		difficulty = d;
	}

	/**
	 * Sets the nest on this node.
	 * @param pNest : the nest.
	 */
	public void setNest(Nest pNest) {
		nest = pNest;
	}

	/** @return the difficulty of this node. */
	public int getDifficulty() {
		return difficulty;
	}

	/**
	 * Sets the difficulty on this node.
	 * @param pDifficulty : the new difficulty.
	 */
	public void setDifficulty(int pDifficulty) {
		difficulty = pDifficulty;
	}

	/** @return true if an ant can walk over this node. */
	public boolean isWalkable() {
		return difficulty < MAX_DIFFICULTY;
	}

	/**
	 * Sets the resource on this node.
	 * @param pResource : the resource.
	 */
	public void setResource(Resource pResource) {
		resource = pResource;
	}

	/** @return the pheromone level. */
	public float getPheromoneLevel() {
		return pheromoneLevel;
	}

	/** Adds pheromones on this node. */
	public void addPheromones() {
		if (pheromoneLevel < MAX_PHEROMONES) {
			pheromoneLevel += 100;
		}
	}

	/** Remove some pheromones. */
	public void dissipatePheromones() {
		if (pheromoneLevel > 0) {
			pheromoneLevel -= 10;
		}
	}

	/**
	 * Add an ant on this node.
	 * @param pAnt : the ant.
	 */
	public void addAnt(Ant pAnt) {
		ants.add(pAnt);
	}

	/** @return the ants on the node, if any. */
	public BlockingQueue<Ant> getAnts() {
		return ants;
	}

	/** @return the resource on the node, if any. */
	public Resource getResource() {
		return resource;
	}

	/** Regenerate the resource, if any. */
	public void regenResource() {
		if (resource != null) {
			resource.regen();
		}
	}

	/** @return the nest on the node, if any. */
	public Nest getNest() {
		return nest;
	}

	/** @return the x coordinate of the node. */
	public int getX() {
		return xPos;
	}

	/** @return the y coordinate of the node. */
	public int getY() {
		return yPos;
	}

	/** @return the a* data. */
	public AStarData getAStarData() {
		return aStarData;
	}

	/**
	 * Compare two nodes with their position (x, y).
	 * @param node : the other node.
	 * @return true if the two nodes have the same position.
	 */
	public boolean equals(Node node) {
		return xPos == node.getX() && yPos == node.getY();
	}

	/** Resets the current node to its initial state. */
	public void reset() {
		aStarData.reset();
		ants.clear();
		pheromoneLevel = 0;
		if (resource != null) resource.reset();
		if (nest != null) nest.reset();
	}
}